#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <math.h>
#include <limits.h>
#include "cpu.h"
#include "mem.h"
#include "rdtsc.h"

#define PAGE_FAULT

int main(int argc, char* argv[])
{
	if(argc != 1)
	{
		perror("invalid arguments");
		exit(-1);
	}

	//	timing mechanism
	unsigned long long cycle_start = 0;
	unsigned long long cycle_end = 0;

	//	page infomation
	unsigned long page_size = PAGE_SIZE;
	unsigned long buffer_size = 0;
	unsigned long page_num = 0; 

	int round = 0;
	while(buffer_size < 512*(1024*1024))
	{
		buffer_size = pow(2, round) * BUFFER_SIZE;
		page_num = buffer_size / page_size;

		#ifndef PAGE_FAULT
		printf("----------------------------------------------------------------------------\n");
		printf("round %d\n", round);
		printf("page_size\t%lu\n", page_size);
		printf("buffer_size\t%lu\n", buffer_size);
		printf("page_num\t%lu\n", page_num);
		printf("----------------------------------------------------------------------------\n");
		#endif

		//	memory allocation and initialization
		unsigned char *buffer = (unsigned char *) malloc(sizeof(unsigned char) * buffer_size);
		if(buffer == NULL)
		{
			perror("malloc failure");
			//	printf("malloc failure\n");
			break;
		}
		memset(buffer, 0, buffer_size);

		/*
		unsigned char *buffer_o = (unsigned char*) malloc(sizeof(unsigned char) * buffer_size);
		if(buffer == NULL)
		{
			perror("malloc failure");
			printf("malloc failure\n");
			break;
		}
		memset(buffer_o, 0, buffer_size);
		*/
		//	page "walk"
		for(int page_cnt = 0; page_cnt < page_num; page_cnt++)
		{
			cycle_start = rdtsc();
			*(buffer + page_cnt) = 1;
			cycle_end = rdtsc();
			//	printf("cycles\t%lld\n", cycle_end - cycle_start);
			double time = (double)(cycle_end - cycle_start)*1000000000 / (double) CPU_FQ;
			#ifdef PAGE_FAULT
			if(time > 10000)
			{
				printf("%d %lf\n", round, time);
			}
			#endif

			#ifndef PAGE_FAULT
			if(time > 500)
			{
				fprintf(stderr, "%d %lf\n", round, time);
			}
			printf("%d\t%lf\n", page_cnt, time);
			#endif
		}

		free(buffer);
		//free(buffer_o);
		//printf("\n\n");
		round++;

	}

	return 1;
}
